import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';

/**
 * 请求日志中间件
 */
export async function loggingMiddleware(fastify: FastifyInstance) {
  // 请求开始时的钩子
  fastify.addHook('onRequest', async (request: FastifyRequest, reply: FastifyReply) => {
    // 添加请求开始时间
    (request as any).startTime = Date.now();
    
    // 生成请求ID
    if (!request.id) {
      (request as any).id = generateRequestId();
    }

    // 记录请求开始
    request.log.info({
      requestId: request.id,
      method: request.method,
      url: request.url,
      headers: sanitizeHeaders(request.headers),
      ip: request.ip,
      userAgent: request.headers['user-agent']
    }, '请求开始');
  });

  // 响应发送前的钩子
  fastify.addHook('onSend', async (request: FastifyRequest, reply: FastifyReply, payload: Buffer) => {
    const duration = Date.now() - ((request as any).startTime || Date.now());
    
    // 记录响应信息
    request.log.info({
      requestId: request.id,
      method: request.method,
      url: request.url,
      statusCode: reply.statusCode,
      duration: `${duration}ms`,
      contentLength: reply.getHeader('content-length') || payload?.length || 0,
      ip: request.ip
    }, '请求完成');

    // 添加响应头
    reply.header('X-Request-ID', request.id);
    reply.header('X-Response-Time', `${duration}ms`);
    
    return payload;
  });

  // 响应错误时的钩子
  fastify.addHook('onError', async (request: FastifyRequest, reply: FastifyReply, error) => {
    const duration = Date.now() - ((request as any).startTime || Date.now());
    
    // 记录错误信息
    request.log.error({
      requestId: request.id,
      method: request.method,
      url: request.url,
      statusCode: reply.statusCode || 500,
      duration: `${duration}ms`,
      error: {
        name: error.name,
        message: error.message,
        stack: error.stack
      },
      ip: request.ip
    }, '请求出错');
  });
}

/**
 * 生成请求ID
 */
function generateRequestId(): string {
  return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

/**
 * 清理敏感头信息
 */
function sanitizeHeaders(headers: Record<string, any>): Record<string, any> {
  const sensitiveHeaders = [
    'authorization',
    'cookie',
    'x-api-key',
    'x-auth-token'
  ];

  const sanitized = { ...headers };
  
  for (const header of sensitiveHeaders) {
    if (sanitized[header]) {
      sanitized[header] = '[REDACTED]';
    }
  }

  return sanitized;
}
